# -*- coding: utf-8 -*-
from typing import List, Optional, Union

from fastapi import APIRouter, Form, HTTPException, status, File, UploadFile
from pydantic import BaseModel, EmailStr

app04 = APIRouter()

"""Response Model 响应模型"""


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    mobile: str = "10086"
    address: str = None
    full_name: Optional[str] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    mobile: str = "10086"
    address: str = None
    full_name: Optional[str] = None


users = {
    "user01": {"username": "user01", "password": "123456", "email": "user01@example.com", "address": "xxxxxx"},
    "user02": {"username": "user02", "password": "123456", "email": "user02@example.com", "full_name": "test"},
}


@app04.post("/response_model", response_model=UserOut, response_model_exclude_unset=True)
async def response_model(user: UserIn):
    """response_model_exclude_unset：表示不包含定义的默认值在响应中，仅包含实际传输的值"""
    print(user.password)
    return users['user01']


@app04.post("/response_model/attributes",
            response_model=UserOut,
            # response_model=Union[UserIn, UserOut],
            # response_model=List[UserOut],  # 符合UserOut模型类的返回成列表
            # response_model_include=['username'],  # 返回内容包含字段
            # response_model_example=['password']   # 返回内容排除字段
            )
async def response_model_attributes(user: UserIn):
    # del user.password  # Union[UserIn, UseOut]后，删除字段
    # return [user, user]  # 返回List
    return user


"""Response Status Code 响应状态码"""


@app04.post('/status_code', status_code=200)
async def status_code():
    return {"status_code": 200}


@app04.post('/status_attributes', status_code=status.HTTP_200_OK)
async def status_attributes():
    return {"status_code": status.HTTP_200_OK}


"""Form Data 表单数据处理"""


@app04.post('/login')
async def login(username: str = Form(...), password: str = Form(...)):
    """Form表单类的校验类似 Query/Path/Cookie"""
    return {"username": username, "password": password}


"""Request Files 单文件，多文件上传及参数详解"""


@app04.post('/file')
async def file_(file: bytes = File(...)):  # 如果上传多文件，使用 files: List[bytes] = File(...)
    """使用File类 文件内容以字节形式读入内存，适用于上传小文件"""
    return {"file_size": len(file)}


@app04.post('/upload_files')
async def upload_files(files: List[UploadFile] = File(...)):  # 如果上传单个文件，使用 files: UploadFile = File(...)
    """
    使用 UploadFile 类的优势：
    1，文件也是先存在内存中，但是达到一定阈值后，将保存在磁盘中
    2，适用于图片，视频文件
    3，可以获取上传的元数据，如文件名，创建时间等
    4，有文件对象的异步接口（可以异步的读取或更改文件内容）
    5，上传的文件是 python 文件对象，可以使用python的操作文件方法，如write()，read()等
    :param files:
    :return:
    """
    for file in files:
        contents = await file.read()  # 异步接口，使用异步方法
        print(contents)
    return {'filename': files[0].filename, "contents_type": files[0].content_type}


"""FastApi 项目的静态文件配置，此部分代码见文件 main.py"""
pass

"""Path Operation Configuration 路径操作配置"""


@app04.post('/path_operation_configuration',
            response_model=UserOut,
            # tags=['Path', 'Operation', 'Configuration'],
            summary="这里可以自定义总结说明",
            description='这里可以自定义接口展开后下方说明',
            deprecated=True,  # 接口注释，如果接口不适用了，直接写上此变量便会注释掉接口
            response_description='这里可以自定义回复说明',
            status_code=200, )
async def path_operation_configuration(user: UserIn):
    """
    路径操作配置
    :param user: 用户信息
    :return:
    """
    return user.dict()


"""Handling Errors 错误处理"""


@app04.get('/http_exception')
async def http_exception(city: str):
    if city != 'Beijing':
        raise HTTPException(status_code=404, detail='City is not found!', headers={'X-Error': 'Error'})
    return {"city": city}


@app04.get('/http_exception/{city_id}')
async def override_http_exception(city_id: int):
    if city_id == 1:
        raise HTTPException(status_code=418, detail="Nope! I don't like 1.")
    return {"city_id": city_id}
